#include "Col.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "Dictionary.h"
#include "Class.h"
#include "DictHashTab.h"

//---- Dictionary --------------------------------------------------------------

NewMetaImpl(Dictionary,Container, (TP(ht)));

Object *Dictionary::ignore= 0;

Dictionary::Dictionary(int initCapacity) : Container()
{
	Init(initCapacity);
}

Dictionary::~Dictionary()
{
	SafeDelete(ht);
}

Object *Dictionary::Clone()
{
	Object *key, *value;

	Dictionary *clone= (Dictionary*) New();
	DictionaryIterator next(this);
	while (key= next()) {
		value= next.GetValue();
		clone->PutAtKeyIfAbsent(value, key);
	}
	return clone;
}

void Dictionary::InitNew()
{
	Container::InitNew();
	Init(cContainerInitCap);
}

void Dictionary::FreeAll()
{
	DictionaryIterator next(this);
	Object *key, *value;

	CheckForIterator("FreeAll");

	while (key= next()) {
		key->FreeAll();
		value= next.GetValue();
		value->FreeAll();
		SafeDelete(key);
		SafeDelete(value);
	}
	Empty(cContainerInitCap);
}

int Dictionary::Capacity()
{
	return ht->Capacity();
}

void Dictionary::Empty(int newCapacity)
{
	CheckForIterator("Empty");

	ht->Empty(newCapacity);
	Changed();
}

void Dictionary::FreeValues()
{
	DictionaryIterator it(this);
	Object *value;

	CheckForIterator("FreeValues");

	while (value= it.NextValue())
		SafeDelete(value);
	Empty(cContainerInitCap);
}

void Dictionary::FreeAllValues()
{
	DictionaryIterator it(this);
	Object *value;

	CheckForIterator("FreeAllValues");

	while (value= it.NextValue()) {
		value->FreeAll();
		SafeDelete(value);
	}
	Empty(cContainerInitCap);
}

Object *Dictionary::PutAtKeyIfAbsent(Object *value, Object *key)
{
	if (IsArgNull("PutAtKeyIfAbsent(value)", value) ||
				IsArgNull("PutAtKeyIfAbsent(key)", key))
		return value;
	CheckForIterator("AddAtKey");

	Object *val= (Object*) ht->AddAt(value, key, FALSE);
	if (! val)
		Changed();
	return val;
}

Object *Dictionary::PutAtKey(Object *value, Object *key)
{
	if (IsArgNull("PutAtKey(value)", value) || IsArgNull("PutAtKey(key)", key))
		return value;
	CheckForIterator("AddAtKey");

	Object *oldValue= (Object*) ht->AddAt(value, key, TRUE);
	if (oldValue != value)
		Changed();
	return oldValue;
}

Object *Dictionary::RemoveKey(Object *key, Object *&value)
{
	if (IsArgNull("RemoveKey", key))
		return 0;
	CheckForIterator("RemoveKey");

	Object *removedKey= (Object*) ht->RemoveKey(key, (void **) &value, eEqValue);
	if (removedKey)
		Changed();
	return removedKey;
}

Iterator *Dictionary::MakeIterator(bool, void *placement)
{
	return new(placement) DictionaryIterator(this);
}

Object *Dictionary::AtKey(Object *key)
{
	return (Object*) ht->AtKey(key, eEqValue);
}

OStream &Dictionary::PrintOn(OStream &os)
{
	Object *key;
	DictionaryIterator next(this);
	Container::PrintOn(os);

	os NL;
	while (key= next())
		os << key SP << next.GetValue() NL;
	return os NL;
}

IStream &Dictionary::ReadFrom(IStream &is)
{
	Object *key, *value;
	int nread, sz;

	Container::ReadFrom(is);
	nread= 0;
	sz= size;
	size= 0;
	while (nread < sz) {
		is >> key >> value;
		nread++;
		PutAtKey(value, key);
	}
	return is;
}

void Dictionary::Init(int initCapacity)
{
	ht= new DictHashTab(
			initCapacity,
			&ContainerTypes::pEqual, &ContainerTypes::pHash,
			&size);
}

Dictionary::Dictionary(Dictionary *) : Container()
{
	ht= 0;
}

//---- DictionaryIterator ------------------------------------------------------

DictionaryIterator::DictionaryIterator(Dictionary *adt)
{
	dt= adt;
	pix= 0;
	ht= 0;
}

DictionaryIterator::~DictionaryIterator()
{
	Terminate();
}

void DictionaryIterator::Reset()
{
	Iterator::Reset();
	pix= 0;
}

Object *DictionaryIterator::operator()()
{
	return NextIndex();
}

Object *DictionaryIterator::NextValue()
{
	if (NextIndex())
		return (Object*) ht->ValueAt(pix);
	return 0;
}

Object *DictionaryIterator::NextKey()
{
	return NextIndex();
}

Object *DictionaryIterator::GetValue()
{
	if (IsActive())
		return (Object*) ht->ValueAt(pix);
	return 0;
}

Container *DictionaryIterator::GetContainer()
{
	return dt;
}

Object *DictionaryIterator::NextIndex()
{
	if (! Activated()) {
		if (Activate()) {
			ht= dt->ht;
			pix= ht->GetInitialIndex();
		}
	}
	if (! Terminated()) {
		Object *op= (Object*) ht->AtNextIndex(pix);
		if (op == 0)
			Terminate();
		return op;
	}
	return 0;
}

